import {
  util_GetRowAttrVal,
  util_OptionChainHack,
  util_GetCurComponentAttrWithInheritedAttr,
} from "@gd-accbuild-ui/gd-ui/utils/index";
import { transName, schemaTools, cloneDeep } from "@gd-accbuild-core/config/utils";
import { globalConfig } from "@gd-accbuild-core/config/index";
import { allOnEventFuncs } from "./useFromDynmicConfig/useFromMergeEventFunc";
import { computed, getCurrentInstance, nextTick } from "vue";
/**
 * 按监听优先级插入
 */
const sortInsertListener = ({ curListener, list = [], idx, indexList = [] }) => {
  const len = list.length;
  if (len === 0 || !curListener.hasOwnProperty("priority")) {
    list.push(curListener);
    indexList.push(idx);
  } else {
    const matchedIdx = list.findIndex((el) => {
      if (el.hasOwnProperty("priority")) {
        return curListener.priority > el.priority;
      } else {
        return false;
      }
    });
    if (matchedIdx === -1 || matchedIdx === len - 1) {
      list.push(curListener);
      indexList.push(idx);
    } else {
      list.splice(matchedIdx, 0, curListener);
      indexList.splice(matchedIdx, 0, idx);
    }
  }
};
/**
 * 获取元匹配事件的匹配监听器 和 没有事件的但匹配元的监听器
 */
const getMatchMetaAllListeners = ({ configObj, eventNames = [] }) => {
  const matchedListeners = {};
  const restListeners = {};
  Array.isArray(configObj.metaItemList) &&
    configObj.metaItemList.forEach((el, idx) => {
      if (Array.isArray(el.metaEventListeners)) {
        el.metaEventListeners.forEach((el2) => {
          const isMatched = el2.metaKey === configObj.metaKey && eventNames.includes(el2.eventName);
          const isMatchedRest =
            el2.metaKey === configObj.metaKey &&
            !eventNames.includes(el2.eventName) &&
            el2.eventName !== "_modelValueChange";
          if (isMatched) {
            if (!matchedListeners.hasOwnProperty(el2.eventName)) {
              matchedListeners[el2.eventName] = {
                list: [],
                cacheMatchMetaItemIdx: [],
              };
            }
            sortInsertListener({
              curListener: el2,
              list: matchedListeners[el2.eventName].list,
              idx,
              indexList: matchedListeners[el2.eventName].cacheMatchMetaItemIdx,
            });
          } else if (isMatchedRest) {
            if (!restListeners.hasOwnProperty(el2.eventName)) {
              restListeners[el2.eventName] = {
                list: [],
                cacheMatchMetaItemIdx: [],
              };
            }
            sortInsertListener({
              curListener: el2,
              list: restListeners[el2.eventName].list,
              idx,
              indexList: restListeners[el2.eventName].cacheMatchMetaItemIdx,
            });
          }
        });
      }
    });
  return {
    matchedListeners,
    restListeners,
  };
};
/**
 * 通过加入监听器 增强事件
 */
const getEnhanceEventByListener = ({ configObj, tempFunc, allListeners = [], cacheMatchMetaItemIdx = [] }) => {
  const len = allListeners.length;
  return async (value) => {
    for (let i = 0; i < len; i++) {
      const item = allListeners[i];
      if ((i === 0 && item.priority > 0) || item.priority === undefined) {
        await (async (value) => tempFunc({ ...configObj, value }))(value);
      }
      const params = {
        rowIdx: configObj["rowIdx"],
        colIdx: configObj["colIdx"],
        metaKey: configObj.metaItemList[cacheMatchMetaItemIdx[i]].key,
        metaItem: configObj.metaItemList[cacheMatchMetaItemIdx[i]],
        metaItemList: configObj["metaItemList"],
        rowData: configObj["rowData"],
        formData: configObj["formData"],
        tableBodyData: configObj["tableBodyData"],
      };
      const itemFunc = schemaTools.getFunc(item.func);
      if (!item.blocked) {
        itemFunc({
          ...configObj,
          ...params,
          sourceMetaEventConfigObj: {
            value,
            metaKey: configObj.metaItem.key,
            metaItem: configObj.metaItemmetaItem,
          },
        });
      } else {
        await (async (value) => itemFunc({ ...configObj, value }))(value);
      }
      if (item.priority < 0 && len - 1 >= i + 1) {
        await (async (value) => tempFunc({ ...configObj, value }))(value);
      }
    }
  };
};
const interceptTransEvents = (tempEvents, configObj) => {
  if (typeof tempEvents === "object") {
    let funcEvents = {};
    const eventNames = Object.keys(tempEvents);
    const allListenersInfo = getMatchMetaAllListeners({ configObj, eventNames });
    ////
    const allMatchedListenerEventKeys = Object.keys(allListenersInfo.matchedListeners);
    allMatchedListenerEventKeys.forEach((eventName) => {
      const tempFunc = schemaTools.getFunc(tempEvents[eventName]);
      funcEvents[eventName] = getEnhanceEventByListener({
        configObj,
        tempFunc,
        eventName,
        allListeners: allListenersInfo.matchedListeners[eventName].list,
        cacheMatchMetaItemIdx: allListenersInfo.matchedListeners[eventName].cacheMatchMetaItemIdx,
      });
    });
    ////
    const allRestListenerEventKeys = Object.keys(allListenersInfo.restListeners);
    allRestListenerEventKeys.forEach((eventName) => {
      const tempFunc = () => {};
      funcEvents[eventName] = getEnhanceEventByListener({
        configObj,
        tempFunc,
        eventName,
        allListeners: allListenersInfo.restListeners[eventName].list,
        cacheMatchMetaItemIdx: allListenersInfo.restListeners[eventName].cacheMatchMetaItemIdx,
      });
    });
    ////
    eventNames.forEach((eventName) => {
      if (!funcEvents.hasOwnProperty(eventName)) {
        funcEvents[eventName] = schemaTools.getFunc(tempEvents[eventName]);
      }
    });
    return funcEvents;
  } else if (typeof tempEvents === "function") {
    return interceptTransEvents(tempEvents(configObj), configObj);
  } else {
    return ((configObj) => ({}))(configObj);
  }
};
/**
 * 获取绑定的事件
 * @param {Object} props  来自 props 或 attrs
 * @param {Array} compAttrsKeyPath 组件的事件属性的路径
 * @param {boolean} isCamel 用以区分props参数来自 props 还是 attrs
 * 注意:参数 rowIdx、colIdx、metaKey是基本类型，不会响应式
 */
export const getAllBindEvents = (props, isCamel = true, compAttrsKeyPath = ["events"], appendParams = {}) => {
  const metaItemAlias = isCamel ? "metaItem" : transName("metaItem", "Camel", "Kebab");
  const rowIdxAlias = isCamel ? "rowIdx" : transName("rowIdx", "Camel", "Kebab");
  const colIdxAlias = isCamel ? "colIdx" : transName("colIdx", "Camel", "Kebab");
  const metaItemListAlias = isCamel ? "metaItemList" : transName("metaItemList", "Camel", "Kebab");
  const rowDataAlias = isCamel ? "rowData" : transName("rowData", "Camel", "Kebab");
  const formDataAlias = isCamel ? "formData" : transName("formData", "Camel", "Kebab");
  const tableBodyDataAlias = isCamel ? "tableBodyData" : transName("tableBodyData", "Camel", "Kebab");
  let tempEvents = util_OptionChainHack(
    props[metaItemAlias],
    compAttrsKeyPath,
    ({ rowIdx, colIdx, metaKey, metaItem, metaItemList, rowData, formData, tableBodyData, vm, globalConfig }) => ({})
  );
  return interceptTransEvents(tempEvents, {
    rowIdx: props[rowIdxAlias],
    colIdx: props[colIdxAlias],
    metaKey: props[metaItemAlias].key,
    metaItem: props[metaItemAlias],
    metaItemList: props[metaItemListAlias],
    rowData: props[rowDataAlias],
    formData: props[formDataAlias],
    tableBodyData: props[tableBodyDataAlias],
    ...appendParams,
  });
};
/**
 * 获取每个插槽对应的绑定事件
 * @param {Object} props  来自 props
 */
const getAllBindSlotEventsMapping = (props, appendParams) => {
  const allCompAttrs = props["metaItem"]?.componentAttr ?? {};
  const matchSlotKeys = Object.keys(allCompAttrs).filter(
    (k) => allCompAttrs[k] && allCompAttrs[k].hasOwnProperty("contentType") && allCompAttrs[k].hasOwnProperty("value")
  );
  const ret = {};
  matchSlotKeys.forEach((k) => {
    const kebabKey = transName(k, "Camel", "Kebab");
    ret[kebabKey] = getAllBindEvents(props, true, ["componentAttr", k, "events"], appendParams);
  });
  return ret;
};
///////////////////////////
/**
 * 自动提交事件: 用于可编辑表格时,修改cell后自动提交请求;不同类型组件 自动触发时机不一样
 */
const AutoSubmitEvent_AllowInEvent = {
  change: ["Cascader", "Select", "Switch"],
  blur: ["Input"],
};
const AutoSubmitEvent_AllowInEventKeys = Object.keys(AutoSubmitEvent_AllowInEvent);
const allOnEventFuncKeys = Object.keys(allOnEventFuncs);
/**
 * 是否立即执行事件
 */
const isImmediateExecuteEvent = ({ eventName }) => {
  eventName === "change";
};
//////////////////////////
/**
 * 获取所有绑定的事件;该方法仅返回原子组件的事件,去掉了bizUi的事件
 */
export default (props, curBindVal) => {
  const { proxy: vm } = getCurrentInstance();
  /**
   * 获取直传的绑定的事件
   */
  const allBindEvents = getAllBindEvents(props, true, ["events"], {
    vm,
    globalConfig,
  });

  /////////////////////////////////////////
  /**
   * 具体增强事件函数:自动提交
   */
  const autoSubmitEventFunc = () => {
    if (props.itemSubmitConfig.allowAutoSubmit) {
      let updateData = {};
      if (props.rowIdx >= 0) {
        updateData = props.rowData;
      } else {
        updateData = props.formData;
      }
      nextTick(() => {
        globalConfig.update({
          moduleCode: props.itemSubmitConfig.moduleCode,
          vmCode: props.itemSubmitConfig.vmCode,
          data: {
            ...updateData,
          },
          vmTemplateConfig: props.vmTemplateConfig,
        });
      });
    }
  };
  ////////////////////////////////////
  /**
   * 定义后置事件增强回调
   * 如果不同组件增强不同,则可以用metaItem.type区分
   */
  const doEnhanceEvent = (eventName) => {
    if (AutoSubmitEvent_AllowInEvent[eventName].includes(props.metaItem.type)) {
      autoSubmitEventFunc();
    }
  };

  /**
   * 原事件与后置增强事件 组合
   */
  AutoSubmitEvent_AllowInEventKeys.forEach((eventName) => {
    if (allBindEvents.hasOwnProperty(eventName)) {
      const orgEvent = allBindEvents[eventName];
      delete allBindEvents[eventName];
      allBindEvents[eventName] = (value) => {
        orgEvent(value);
        doEnhanceEvent(eventName);
      };
      //change事件通常一开始需要调用 // FIXME: 只有标记立即执行的才需要马上调用
      if (isImmediateExecuteEvent({ eventName })) {
        orgEvent(curBindVal.value);
      }
    } else {
      if (AutoSubmitEvent_AllowInEvent[eventName].includes(props.metaItem.type)) {
        allBindEvents[eventName] = (value) => {
          doEnhanceEvent(eventName);
        };
      }
    }
  });
  // dynmicConfig中的事件;改优先级低于events:{}中配置的事件;即一旦events中配置了对应事件,dynmicConfig事件将不生效
  // 线上事件的元数据放在dynmicConfig中;本地开发自动提取到events:{}中
  allOnEventFuncKeys.forEach((eventName) => {
    if (!allBindEvents.hasOwnProperty(eventName)) {
      allBindEvents[eventName] = allOnEventFuncs[eventName]({ props });
      //change事件通常一开始需要调用 // FIXME: 只有标记立即执行的才需要马上调用
      if (isImmediateExecuteEvent({ eventName })) {
        allBindEvents[eventName](curBindVal.value);
      }
    }
  });
  ////////
  const allBindEventsName = Object.keys(allBindEvents);
  //删除bizUi的相关事件
  allBindEventsName.forEach((eventName) => {
    if (eventName.startsWith("onBizUi")) {
      delete allBindEvents[eventName];
    }
  });
  const allBindSlotEventsMapping = computed(() => {
    return getAllBindSlotEventsMapping(props, { vm, globalConfig });
  });
  const getBindSlotEvents = (key) => {
    return allBindSlotEventsMapping.value.hasOwnProperty(key) ? allBindSlotEventsMapping.value[key] : {};
  };
  return { allBindEvents, getBindSlotEvents };
};
